﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using BMC.ARSystem;
using Wicresoft.CustomerAttributes;

namespace Wicresoft.ARConnector
{
    public class ARProxy<T> : IDisposable
    {
        protected string UserName { get; set; }

        protected string Password { get; set; }

        protected string ServerName { get; set; }

        protected string Authentication { get; set; }

        public bool EnableTransaction { get; set; }

        protected Server ServerManager
        {
            // get { return new ARServerManagement().GetServer(); }
            get { return SingletonARServer.Server; }
        }

        private Server arServer;

        public ARProxy(string userName, string password, string serverName, string authentication)
        {
            this.UserName = userName;
            this.Password = password;
            this.ServerName = serverName;
            this.Authentication = authentication;
            this.arServer = new BMC.ARSystem.Server();
            Login();
        }

        private bool Login()
        {
            bool isLogin = false;
            if (!string.IsNullOrEmpty(this.ServerName) && !string.IsNullOrEmpty(this.UserName) && !string.IsNullOrEmpty(this.Password))
            {
                try
                {
                    arServer.Login(this.ServerName, this.UserName, this.Password, this.Authentication);
                    isLogin = true;
                }
                catch (ARException are)
                {

                    throw are;

                }

            }
            return isLogin;
        }


        public void LogOut()
        {
            arServer.Logout();
        }


        //public IList<T> GetEntryList()
        //{
        //    T t =  default(T);
        //    string name = FindFormName(t);
        //    if(name == null)
        //    {
        //        throw new ArgumentNullException("Form name cannot be null!");
        //    }
        //    var orginalList =  arServer.GetListEntry(name,string.Empty);
            
        //    foreach (var item in orginalList)
        //    {
                
        //    }
        //}


        /// <summary>
        /// Add data to AR for single entity without transaction
        /// </summary>
        /// <param name="entity"></param>
        public virtual void CreateEntry(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("Entity cannot be null!");
            }
            try
            {
                string name = FindFormName(entity);
                if (string.IsNullOrEmpty(name))
                {
                    throw new ArgumentNullException("Entity id or form name cannot be null!");
                }
                FieldValueList list = BuildFiedList(entity, true);
                if (list != null)
                {
                    arServer.CreateEntry(name, list);                    
                }
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// Add list data to AR with tranaction,if any error occured ,the action will rollback
        /// </summary>
        /// <param name="entityList"></param>
        public virtual void CreateEntry(IList<T> entityList)
        {
            if (entityList == null)
            {
                throw new ArgumentNullException("list cannot be null!");
            }
            try
            {
                if (EnableTransaction)
                {
                    arServer.BeginBulkEntryTransaction();
                }
                foreach (T item in entityList)
                {
                    CreateEntry(item);
                }
                if (EnableTransaction)
                {
                    arServer.SendBulkEntryTransaction();
                }
            }
            catch
            {
                if (EnableTransaction)
                {
                    arServer.CancelBulkEntryTransaction();
                }
                throw;
            }
        }

        /// <summary>
        /// Update data to AR for single entity
        /// </summary>
        /// <param name="entity"></param>
        public virtual void UpdateEntry(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(entity.ToString());
            }
            try
            {
                string name = FindFormName(entity);
                string id = FindEntryId(entity);
                if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(id))
                {
                    throw new ArgumentNullException("Entity id or form name cannot be null!");
                }
                FieldValueList list = BuildFiedList(entity, false);
                if (list != null)
                {
                    arServer.SetEntry(name, id, list);
                }
            }
            catch
            {
                throw;
            }

        }

        /// <summary>
        /// Delete single entity from AR
        /// </summary>
        /// <param name="entity"></param>
        public virtual void RemoveEntry(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(entity.ToString());
            }
            try
            {
                string name = FindFormName(entity);
                string id = FindEntryId(entity);
                if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(id))
                {
                    throw new ArgumentNullException("Entity id or form name cannot be null!");
                }
                arServer.DeleteEntry(name, id);
            }
            catch
            {
                throw;
            }

        }

        /// <summary>
        /// Delete list data from AR with transaction
        /// </summary>
        /// <param name="entityList"></param>
        public virtual void RemoveEntry(IList<T> entityList)
        {
            if (entityList == null)
            {
                throw new ArgumentNullException("Entity list cannot be null!");
            }
            try
            {
                if (EnableTransaction)
                {
                    arServer.BeginBulkEntryTransaction();
                }
                foreach (var item in entityList)
                {
                    RemoveEntry(item);
                }
                if (EnableTransaction)
                {
                    arServer.SendBulkEntryTransaction();
                }

            }
            catch
            {

                throw;
            }
        }

        private FieldValueList BuildFiedList(T entity, bool isNewItem)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(entity.ToString());
            }
            FieldValueList list = new FieldValueList();
            try
            {
                foreach (PropertyInfo item in typeof(T).GetProperties())
                {
                    var fieldAttribute = item.GetCustomAttributes(false).FirstOrDefault(a => a is ARFieldAttribute) as ARFieldAttribute;
                    if (fieldAttribute != null)
                    {
                        if (isNewItem || (!isNewItem && fieldAttribute.AllowModify))
                        {
                            uint id = Convert.ToUInt32(fieldAttribute.Id);
                            int type = (int)(fieldAttribute.Type);
                            var originalValue = item.GetValue(entity, null);
                            object newValue = originalValue;
                            if (originalValue != null && fieldAttribute.MaxLength > 0)
                            {
                                if (originalValue.ToString().Length > fieldAttribute.MaxLength)
                                {
                                    newValue = originalValue.ToString().Substring(0, fieldAttribute.MaxLength - 1);
                                }

                            }
                            list.Add(id, newValue, type);
                        }
                    }
                }
            }
            catch (Exception)
            {

                throw;
            }
            return list;
        }

        private string FindEntryId(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(entity.ToString());
            }
            //typeof(T).GetCustomAttributes(false).FirstOrDefault(e => e is AREntryIdAttribute);
            string id = string.Empty;
            foreach (PropertyInfo item in typeof(T).GetProperties())
            {
                foreach (Attribute a in item.GetCustomAttributes(false))
                {
                    if (a is AREntryIdAttribute)
                    {
                        id = item.GetValue(entity, null).ToString();
                        break;
                    }
                }
            }
            return id;
        }

        private string FindFormName(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(entity.ToString());
            }
            string name = string.Empty;
            var formAttribute = typeof(T).GetCustomAttributes(false).Where(a => a is ARFormAttribute).FirstOrDefault() as ARFormAttribute;
            if (formAttribute != null)
            {
                name = formAttribute.Name;
            }
            return name;
        }

        public void Dispose()
        {
            LogOut();
        }
    }
}
